package com.ciei.dpagm.util;

import com.baomidou.mybatisplus.annotation.TableName;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.*;

/**
 * CSV工具类
 * @author 方诺舟
 * @date 2020/08/05
 */
public class CSVUtils {

    private static Logger logger = LoggerFactory.getLogger(CSVUtils.class);

    /**
     * 功能说明：获取UTF-8编码文本文件开头的BOM签名。
     * BOM(Byte Order Mark)，是UTF编码方案里用于标识编码的标准标记。例：接收者收到以EF BB BF开头的字节流，就知道是UTF-8编码。
     * @return UTF-8编码文本文件开头的BOM签名
     */
    public static String getBOM() {
        byte[] b = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
        return new String(b);
    }

    /**
     * 生成CSV文件
     * @param exportData    源数据List
     * @param headerList    csv文件的列表头List
     * @param outPutPath    文件路径
     * @param fileName      文件名称
     * @return              生成的文件
     */
    public static File createCsvFile(List<Map<String, String>> exportData, List<String> headerList, String outPutPath, String fileName) {
        if (exportData.isEmpty() || headerList.isEmpty() || StringUtils.isBlank(outPutPath) || StringUtils.isBlank(fileName)) {
            return null;
        }
        File csvFile = null;
        BufferedWriter csvFileOutputStream = null;
        try {
            File file = new File(outPutPath);
            if (!file.exists()) {
                file.mkdirs();
            }
            //定义文件名格式并创建
            StringBuilder filePath = new StringBuilder(outPutPath);
            if (!outPutPath.endsWith("/")) {
                filePath.append("/");
            }
            filePath.append(fileName);
            if (!fileName.endsWith(".csv")) {
                filePath.append(".csv");
            }
            csvFile = new File(filePath.toString());
            file.createNewFile();
            // UTF-8使正确读取分隔符","
            //如果生产文件乱码，windows下用gbk，linux用UTF-8
            csvFileOutputStream = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(csvFile), StandardCharsets.UTF_8), 1024);

            //写入前段字节流，防止乱码
            //csvFileOutputStream.write(getBOM());
            // 写入文件头部
            Iterator<String> propertyIterator = headerList.iterator();
            while (propertyIterator.hasNext()) {
                String property = propertyIterator.next();
                csvFileOutputStream.write(property == null ? "" : property);
                if (propertyIterator.hasNext()) {
                    csvFileOutputStream.write(",");
                }
            }
            csvFileOutputStream.newLine();
            // 写入文件内容
            Iterator<Map<String, String>> iterator = exportData.iterator();
            while (iterator.hasNext()) {
                Map<String, String> row = iterator.next();
                propertyIterator = headerList.iterator();
                while (propertyIterator.hasNext()) {
                    String property = propertyIterator.next();
                    String str = row == null ? "" : row.get(property);
                    if (StringUtils.isEmpty(str)) {
                        str = "";
                    } else {
                        // 将CSV分隔符（逗号）替换为“|”
                        str = str.replaceAll(",", "|");
                    }
                    csvFileOutputStream.write(str);
                    if (propertyIterator.hasNext()) {
                        csvFileOutputStream.write(",");
                    }
                }
                if (iterator.hasNext()) {
                    csvFileOutputStream.newLine();
                }
            }
            csvFileOutputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (csvFileOutputStream != null) {
                try {
                    csvFileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return csvFile;
    }

    /**
     * 根据实体生成CSV文件
     * @param entityClass       实体类型
     * @param entityData        实体数据
     * @param outPutPath        文件路径
     * @param fileName          文件名称
     * @param <T>               实体泛型
     * @return                  生成的文件
     */
    public static <T> File createCsvFile(Class<T> entityClass, List<T> entityData, String outPutPath, String fileName) {
        if (!entityClass.isAnnotationPresent(TableName.class)) {
            // 不为实体则直接返回
            return null;
        }
        if (entityData.isEmpty()) {
            return null;
        }
        List<Map<String, String>> exportData = new ArrayList<>();
        Method[] methods = entityClass.getMethods();
        for (T entity : entityData) {
            Field[] fields = entity.getClass().getDeclaredFields();
            Map<String, String> map = new HashMap<>(16);
            // 使用反射构建CSV源数据
            for (Field field : fields) {
                // 获取属性名
                String name = field.getName();
                // 首字母转大写
                String methodName = "get" + name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase());
                try {
                    Method method = Arrays.stream(methods).filter(m -> methodName.equals(m.getName())).findFirst().orElse(null);
                    if (method != null) {
                        Object value = method.invoke(entity);
                        map.put(name, value == null ? "" : value.toString());
                    }
                } catch (IllegalAccessException | InvocationTargetException e) {

                }
            }
            exportData.add(map);
        }
        Map<String, String> data = exportData.get(0);
        List<String> headerList = new ArrayList<>(data.keySet());

        return createCsvFile(exportData, headerList, outPutPath, fileName);
    }

    /**
     * 将CSV文件中的数据转换为实体
     * @param entityClass       实体类型
     * @param filePath          文件路径
     * @param fileName          文件名称
     * @param <T>               实体泛型
     * @return                  转换后的实体列表
     */
    public static <T> List<T> csvFileToEntity(Class<T> entityClass, String filePath, String fileName) {
        List<T> entityList = new ArrayList<>();
        if (StringUtils.isBlank(filePath) || StringUtils.isBlank(fileName)) {
            return entityList;
        }
        StringBuilder csvFilePath = new StringBuilder(filePath);
        if (!filePath.endsWith("/")) {
            csvFilePath.append("/");
        }
        csvFilePath.append(fileName);
        if (!fileName.endsWith(".csv")) {
            csvFilePath.append(".csv");
        }
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(csvFilePath.toString()), StandardCharsets.UTF_8))) {
            String line = reader.readLine();
            if (StringUtils.isNotEmpty(line)) {
                String[] headers = line.split(",");
                while ((line = reader.readLine()) != null) {
                    // 分割字符串，保留尾部的空字符串
                    String[] datas = line.split(",", -1);
                    T entity = entityClass.newInstance();
                    for (int i = 0; i < headers.length; i++) {
                        String data = datas[i].replaceAll("\\|", ",");
                        Field  field = entity.getClass().getDeclaredField(headers[i]);
                        String methodName = "set" + headers[i].replaceFirst(headers[i].substring(0, 1), headers[i].substring(0, 1).toUpperCase());
                        Method method = entity.getClass().getMethod(methodName, field.getType());
                        method.invoke(entity, ConvertUtil.convertTypeValue(data, field.getType()));
                    }
                    entityList.add(entity);
                }
            }
        } catch (IOException | InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException | NoSuchFieldException | ParseException e) {
            logger.error("解析CSV文件失败", e);
        }
        return entityList;
    }
}
